package org.autoparser.exttree;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import org.autoparser.exttree.attributes.ZExtAttribute;
import org.autoparser.exttree.attributes.ZExtRegexAttribute;
import org.autoparser.exttree.termoper.ZExtractTerms;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Tag;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasChildFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;


public class ZExtTreeNode {
	private String tagName;
	private Vector<ZExtAttribute> attributes;
	private Vector<ZExtTreeNode> childs;
	private ZExtractTerms extterms;
	private boolean hasParent;
	private int order;
	public ZExtractTerms getExtterms() {
		return extterms;
	}
	public Vector<ZExtTreeNode> getChilds() {
		return childs;
	}
	
	public boolean isHasParent() {
		return hasParent;
	}
	protected ZExtTreeNode(){
		attributes = new Vector<ZExtAttribute>();
		childs = new Vector<ZExtTreeNode>();
		hasParent = false;
		order = -1;
	}
	public ZExtTreeNode(Element ele){
		attributes = new Vector<ZExtAttribute>();
		childs = new Vector<ZExtTreeNode>();
		hasParent = false;
		order = -1;
		init(ele);
	}
	private void initAttributes(List list){
		if(list != null && list.size() > 0){
			HashMap<String,ZExtAttribute> attMap = new HashMap<String,ZExtAttribute>();
			for(int i = 0; i < list.size(); ++i){
				String name = ((Attribute)(list.get(i))).getName();
				String value = ((Attribute)(list.get(i))).getValue();
				if(name.compareToIgnoreCase("regex") == 0){
					for(String s: value.split(";")){
						ZExtAttribute tmp = attMap.get(s.trim());
						if(tmp != null)
							attMap.put(s.trim(), new ZExtRegexAttribute(tmp));
					}
					continue;
				}
				else if(name.compareToIgnoreCase("HasParent") == 0){
					if(value.trim().compareToIgnoreCase("true") == 0)
						hasParent = true;
					continue;
				}
				else if(name.compareToIgnoreCase("Order") == 0){
					try{
						order = Integer.parseInt(value.trim());
					}catch(NumberFormatException e){
						order = -1;
					}
					continue;
				}
				ZExtAttribute att = new ZExtAttribute(name,value);
				attMap.put(name, att);
			}
			for(ZExtAttribute e: attMap.values())
				attributes.add(e);
		}
	}
	private void initChildsAndExts(List list){
		if(list != null && list.size() > 0){
			for(int i = 0; i < list.size(); ++i){
				Element ele = (Element)(list.get(i));
				if(ele.getName().compareToIgnoreCase("extraction") == 0){
					extterms = ZExtractTerms.CreateExtractTerms(ele);
					continue;
				}
				childs.add(new ZExtTreeNode(ele));
			}
		}
	}
	protected void init(Element ele){
		tagName = ele.getName();
		initAttributes(ele.attributes());
		initChildsAndExts(ele.elements());
	}
	public void extractTerm(Node node){
		if(extterms != null)
			extterms.extractTerms(node);
	}
	
	public int getOrder() {
		return order;
	}
	public NodeFilter getFilter(){
		TagNameFilter tagFilter = new TagNameFilter(tagName);
		if(attributes.size() == 0)
			return tagFilter;
		Vector<NodeFilter> filters = new Vector<NodeFilter>();
		filters.add(tagFilter);
		for(int i = 0; i < attributes.size(); ++i)
			filters.add(attributes.get(i).getFilter());
		
		for(ZExtTreeNode tn: this.getChilds())
			if(tn.isHasParent()){
				filters.add(new HasChildFilter(tn.getFilter()));
			}
		NodeFilter []filterArry = new NodeFilter[filters.size()];
		for(int i = 0; i < filters.size(); ++i)
			filterArry[i] = filters.elementAt(i);
		return new AndFilter(filterArry);
	}
	public NodeFilter getNextFilter(){
		if(childs.size() == 0)
			return null;
		NodeFilter []filters = new NodeFilter[childs.size()];
		for(int i = 0; i < childs.size(); ++i)
			filters[i] = childs.get(i).getFilter();
		return new OrFilter(filters);
	}
	public boolean isTagSatisfy(Tag tag){
		return isTagSatisfy(tag,false);
	}
	public boolean isTagSatisfy(Tag tag,boolean caseSensitive){
		if(tag.getTagName().compareToIgnoreCase(tagName) != 0)
			return false;
		else{
			for(ZExtAttribute att: attributes)
				if(!att.isAttSatisfy(tag, caseSensitive))
					return false;
		}
		return true;
	}
}
